#include "AppClient.h"
#include <iostream>

AppClient::AppClient(){
    this->cli = new TcpClient();
    TcpClient* cli = this->cli;

    cli->onConnection = [](const SocketChannelPtr& channel) {
        std::string peeraddr = channel->peeraddr();
        if (channel->isConnected()) {
            printf("connected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
        } else {
            printf("disconnected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
            printf("prepare for reconnect\n");
        }
    };
    cli->onMessage = [](const SocketChannelPtr& channel, Buffer* buf) {
        printf("receive data from server: %.*s", (int)buf->size(), (char*)buf->data());
    };

    ReconnectInfo reconn;
    reconn.min_delay = 1000;
    reconn.max_delay = 10000;
    reconn.delay_policy = 2;
    cli->setReconnect(&reconn);       
}

AppClient::~AppClient() {
    this->cli->stop();
}

void AppClient::connect(int port) {    
    int connfd = cli->createsocket(port);
    if (connfd < 0) {
        throw "could not connect to server";
    }
    cli->start();
}

void AppClient::onMessage(std::function<void(const AppClient&, json)> const &f) {
    this->cli->onMessage = [this, f](const hv::SocketChannelPtr& ch, Buffer* buf){
        char* data = (char*) malloc((int) buf->size() + 1);
        memcpy(data, buf->data(), (int) buf->size());
        data[(int) buf->size()] = '\0';
        printf("new message: %s\n", data);
        f(*this, json::parse(data));
        free(data);
    };
}

void AppClient::onConnection(std::function<void(const hv::SocketChannelPtr&)> const &f) {
    this->cli->onConnection = f;
}

bool AppClient::doSend(std::string msg) const {
    if (this->cli->channel->isConnected()) {
        int len = msg.length();
        char* data = (char*) malloc(len + 4);
        int bigLen = htonl(len);
        memcpy(data, &bigLen, 4);
        memcpy(data + 4, msg.c_str(), len);
        this->cli->channel->write(data, len + 4);
        free(data);
        return true;
    }
    printf("could not send msg '%s', have not connected to server\n", msg.c_str());
    return false;
}

bool AppClient::send(json msg) const {
    msg["code"] = (msg["code"].is_null() ? CODE_SUCCESS : msg["code"]);
    if (this->doSend(msg.dump())) {
        printf("send msg %s\n", msg.dump().c_str());
        return true;
    }
    return false;
}
void test() {
    AppClient client;
    client.onConnection([](const SocketChannelPtr& channel) {
        std::string peeraddr = channel->peeraddr();
        if (channel->isConnected()) {
            printf("connected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
        } else {
            printf("disconnected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
            printf("prepare for reconnect\n");
        }
    });
    client.onMessage([](const AppClient& c, json msg) {
        printf("receive data from server: %s\n", msg.dump().c_str());
        auto j = msg;
        if ((int) j["code"] == 1000) {
            printf("code: %d\n", (int) j["code"]);
            if ((int) j["command"] == GET_INFO) {
                printf("receive server command GET_INFO\n");
            }
        }
    });
    client.connect(25539);

    for(;;) {
        json resp;
        resp["uuid"] = "test-uuid";
        resp["mac"] = "test-mac";
        resp["client_name"] = "test-name";
        resp["code"] = CODE_SUCCESS;
        if (client.send(resp)) {
            printf("send %s\n", resp.dump().c_str());
        }
        hv_sleep(5);
    }
    while (1) hv_sleep(1);
}